#include "game_socket.h"
#include <arpa/inet.h>
#include <sys/socket.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "game_macros.h"
#include "game_thread.h"
#include <event2/bufferevent.h>
#include <unistd.h>
#include <errno.h>
#include "game_version.h"
#include "game_ev.h"

void CGameSocket::onClose(){
  __log("%s","CGameSocket::onClose");
}

void CGameSocket::onRead(bufferevent *bev){
  __log("%s","CGameSocket::onRead");
}
void CGameSocket::onEvents(bufferevent* bev,short events){
  if (events & BEV_EVENT_EOF){
    onClose();
  }else if (events & BEV_EVENT_ERROR)
    printf("some other error\n");
}



int CGameSocket::connect(sockfd_t fd,const char *addr, int port){
  int ret = -1;
  do{

    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr(addr);
    serv_addr.sin_port = htons(port);



    CC_BREAK_IF_LOG(0 > (ret = ::connect(fd,(struct sockaddr *)&serv_addr, sizeof(serv_addr))),"Error when connect: [%d]%s", errno, strerror(errno));
    evutil_make_socket_nonblocking(fd);


    // _ctx->_ev = event_new(_ctx->_evbase, fd,EV_READ | EV_PERSIST,_evsocket_read_cb<CGameSocket, &CGameSocket::onRead>, _ctx);
    // _ctx->_ev = event_new(_ctx->_evbase, fd,EV_READ | EV_PERSIST,CGame::Socket::__socket_read_cb<CGameSocket, &CGameSocket::onRead>, _ctx);
    // _ctx->_master = this;

    // event_add(_ctx->_ev,NULL);


    _bev = bufferevent_socket_new(_evbase, fd, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE);
    bufferevent_setcb(_bev, CGame::Socket::__socketd_read_cb<CGameSocket, &CGameSocket::onRead>, NULL, CGame::Socket::__socketd_events_cb<CGameSocket, &CGameSocket::onEvents>, this);
    bufferevent_enable(_bev, EV_READ | EV_PERSIST);
    _connected = TRUE;
    return fd;
  }while (true);

  return ret;

}

BOOL CGameSocket::init(){
  return init(g_CGameEV.getBase());
}

BOOL CGameSocket::init(event_base* evbase){
  _evbase = evbase;
  return TRUE;
}

sockfd_t CGameSocket::socket(){
  return ::socket(AF_INET, SOCK_STREAM, 0);
}

sockfd_t CGameSocket::connect(const char *addr, int port)
{
  int fd = socket();
  if (fd < 0) {
    return -1;
  }

  sockfd_t ret = connect(fd,addr, port);
  if (ret < 0) {
    close(fd);
    return ret;
  }

  return fd;
}

BOOL CGameSocket::disconnect()
{
  if (_connected) {
    _connected = FALSE;
  }

  if(NULL != _bev){
    bufferevent_free(_bev);
    _bev = NULL;
  }
  return TRUE;
}



CGameSocket::CGameSocket() : _connected(FALSE) {

}

CGameSocket::~CGameSocket(){
  if(NULL != _bev){
    bufferevent_free(_bev);
    _bev = NULL;
  }
}

void CGameSocket::run(){
  event_base_loop(_evbase,EVLOOP_NONBLOCK);
}




int CGameSocket::send(const void *ptr,int len){
  int ret = 0;
  do{
    CC_BREAK_IF(_bev == nullptr);
    CC_BREAK_IF(0 > (ret = ::bufferevent_write(_bev,ptr,len)));
    return ret;
  }while(true);

  if (ret != 0) {
    __warn("Error when flush: [%d]%s\n", errno, strerror(errno));
  }
  //  ,"Error when flush: [%d]%s\n", errno, strerror(errno));
  return ret;
}


const char* CGameSocket::getName(){
  return "CGameSocket";
}


CGameSocketIO::~CGameSocketIO(){

}



